#include "ConfigFile.h"

#include <sstream>
#include <fstream>

namespace Lame3d
{
	// Entry
	ConfigFile::Entry::Entry(const std::string &v, bool iN)
			: value(v), isNew(iN)
	{
	}
	
	ConfigFile::Entry::~Entry()
	{
	}
	
	ConfigFile::Entry& ConfigFile::Entry::operator=(const std::string& s)
	{
		value = s;
		isNew = false;
		return *this;
	}
	
	ConfigFile::Entry& ConfigFile::Entry::operator=(int i)
	{
		std::stringstream ss;
		ss << i;
		ss >> value;
		isNew = false;
		return *this;
	}
	
	ConfigFile::Entry& ConfigFile::Entry::operator=(float f)
	{
		std::stringstream ss;
		ss << f;
		ss >> value;
		isNew = false;
		return *this;
	}
	
	const std::string& ConfigFile::Entry::String() const
	{
		return value;
	}
	
	int ConfigFile::Entry::Int() const
	{
		int v;
		std::stringstream ss;
		ss << value;
		ss >> v;
		return v;
	}
	
	float ConfigFile::Entry::Float() const
	{
		float f;
		std::stringstream ss;
		ss << value;
		ss >> f;
		return f;
	}
	
	bool ConfigFile::Entry::IsNew() const
	{
		return isNew;
	}
	
	// ConfigFile implementation
	ConfigFile::ConfigFile(const char* name)
			: file(name)
	{
		// load the file
		if(file.SystemExists()) {
			load(file.GetSystemPath());
		}
		if(file.UserExists()) {
			load(file.GetUserPath());
		}
	}
	
	ConfigFile::ConfigFile(const File &f)
			: file(f)
	{
		if(file.SystemExists()) {
			load(file.GetSystemPath());
		}
		if(file.UserExists()) {
			load(file.GetUserPath());
		}
	}
	
	ConfigFile::~ConfigFile()
	{
		Save();
		std::map<std::string, Entry*>::iterator it;
		for(it=entries.begin(); it!=entries.end(); ++it) {
			delete it->second;
		}
	}
	
	ConfigFile::Entry& ConfigFile::operator[](const std::string &key)
	{
		std::map<std::string, Entry*>::iterator it;
		Entry *e;
		
		it = entries.find(key);
		if(it == entries.end()) {
			e = new Entry("", true);
			entries[key] = e;
		} else {
			e = it->second;
		}
		
		return *e;
	}
	
	ConfigFile::Entry* ConfigFile::Find(const std::string &key)
	{
		Entry *e;
		std::map<std::string, Entry*>::iterator it;
		
		it = entries.find(key);
		if(it == entries.end()) {
			e = NULL;
		} else {
			e = it->second;
		}
		
		return e;
	}
	
	void ConfigFile::Save() const
	{
		std::ofstream out(file.GetUserPath().c_str());
		printf("saving to %s\n", file.GetUserPath().c_str());
		std::map<std::string, Entry*>::const_iterator it;
		Entry *cE;
		if(out) {
			it = entries.begin();
			for(;it != entries.end(); ++it) {
				cE = it->second;
				out << it->first << "=";
				out << cE->String() << std::endl;
			}
		} else {
			throw "Error writing config file.";
		}
		out.flush();
		out.close();
	}
	
	void ConfigFile::load(const std::string &s)
	{
		std::ifstream inp(s.c_str());
		while(inp) {
			std::string line;
			std::string key;
			std::string value;
			size_t idx;
			Entry* entry;
			std::stringstream ss;
			
			getline(inp, line);
			// skip comments
			if(line[0] == '#') {
				continue;
			}
			idx = line.find("=");
			if(idx != std::string::npos && idx < line.size()) {
				key = line.substr(0, idx);
				value = line.substr(idx+1);
				entry = new Entry(value, false);
				
				// strip key of spaces
				ss << key;
				ss >> key;
				
				entries[key] = entry;
			}
		}
		inp.close();
	}
}
